"""
音频流播放API接口
"""

from fastapi import APIRouter, HTTPException, status, Depends, WebSocket, WebSocketDisconnect
from fastapi.responses import StreamingResponse
from pydantic import BaseModel, Field
from typing import Optional, List, Dict, Any
import asyncio
import json
import uuid
from datetime import datetime

from ...core.exceptions import (
    ValidationError, 
    NotFoundError,
    BusinessLogicError,
    with_error_handling
)
from ...core.security import (
    get_current_user,
    rate_limit
)
from ...core.logging import audit_logger
from ...services.audio import (
    StreamManager,
    StreamConfig,
    StreamStatus
)
from ...services.tts import tts_service


# 创建路由
router = APIRouter()

# 全局流会话管理
stream_sessions: Dict[str, StreamManager] = {}


# 请求模型
class StreamConfigModel(BaseModel):
    """流配置模型"""
    buffer_size: int = Field(8192, ge=1024, le=65536, description="缓冲区大小")
    max_buffers: int = Field(10, ge=1, le=50, description="最大缓冲数量")
    sample_rate: int = Field(22050, ge=8000, le=48000, description="采样率")
    channels: int = Field(1, ge=1, le=2, description="声道数")
    format: str = Field("wav", pattern="^(wav|mp3|ogg)$", description="音频格式")
    chunk_duration: float = Field(0.1, ge=0.05, le=1.0, description="块时长")
    preload_chunks: int = Field(3, ge=1, le=10, description="预加载块数量")
    auto_reconnect: bool = Field(True, description="自动重连")
    reconnect_delay: float = Field(1.0, ge=0.1, le=10.0, description="重连延迟")


class StreamRequestModel(BaseModel):
    """流请求模型"""
    text: str = Field(..., min_length=1, max_length=10000, description="流式文本")
    voice_id: Optional[str] = Field(None, description="语音ID")
    voice_preset: Optional[str] = Field(None, description="语音预设")
    config: Optional[StreamConfigModel] = Field(None, description="流配置")
    metadata: Optional[Dict[str, Any]] = Field(None, description="元数据")


class AudoBookStreamRequestModel(BaseModel):
    """有声读物流请求模型"""
    audiobook_id: str = Field(..., description="有声读物ID")
    chapter: Optional[int] = Field(None, description="章节号")
    config: Optional[StreamConfigModel] = Field(None, description="流配置")


# 响应模型
class StreamInfoModel(BaseModel):
    """流信息模型"""
    session_id: str
    status: str
    config: Dict[str, Any]
    buffer_info: Dict[str, Any]
    metadata: Optional[Dict[str, Any]]


class StreamStatusModel(BaseModel):
    """流状态模型"""
    status: str
    buffer_size: int
    buffer_duration: float
    is_full: bool
    is_empty: bool


# API端点
@router.post("/start", response_model=StreamInfoModel)
@with_error_handling("start_stream")
@rate_limit(limit=5, window=60)  # 每分钟5个流
async def start_stream(
    request: StreamRequestModel,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """开始音频流"""
    try:
        # 检查TTS服务状态
        if not tts_service.is_initialized:
            raise BusinessLogicError("TTS服务未初始化")
        
        # 生成会话ID
        session_id = str(uuid.uuid4())
        
        # 创建流配置
        config_data = request.config.dict() if request.config else {}
        stream_config = StreamConfig(**config_data)
        
        # 创建流管理器
        stream_manager = StreamManager(stream_config)
        
        # 创建音频源函数
        async def audio_source():
            # 获取语音配置
            voice_profile = None
            if request.voice_id:
                voices = await tts_service.get_available_voices()
                voice_profile = next((v for v in voices if v.id == request.voice_id), None)
            
            # 应用语音预设
            voice_settings = None
            if request.voice_preset:
                await tts_service.set_voice_preset(request.voice_preset)
                voice_settings = tts_service.voice_controller.settings
            
            # 执行TTS
            response = await tts_service.synthesize(
                text=request.text,
                voice_profile=voice_profile,
                voice_settings=voice_settings,
                output_format=stream_config.format
            )
            
            if response.success and response.audio_data:
                return response.audio_data
            else:
                raise BusinessLogicError(f"TTS失败: {response.error_message}")
        
        # 开始流传输
        success = await stream_manager.start_streaming(audio_source)
        
        if not success:
            raise BusinessLogicError("启动流传输失败")
        
        # 保存会话
        stream_sessions[session_id] = stream_manager
        
        # 记录审计日志
        audit_logger.log_user_action(
            user_id=current_user.get("sub"),
            action="start_stream",
            resource="streaming",
            details={
                "session_id": session_id,
                "text_length": len(request.text),
                "voice_id": request.voice_id
            }
        )
        
        return StreamInfoModel(
            session_id=session_id,
            status=stream_manager.status.value,
            config=stream_config.__dict__,
            buffer_info=stream_manager.get_buffer_info(),
            metadata=request.metadata
        )
        
    except Exception as e:
        if isinstance(e, (ValidationError, BusinessLogicError)):
            raise
        raise BusinessLogicError(f"启动音频流失败: {str(e)}")


@router.post("/audiobook/{audiobook_id}", response_model=StreamInfoModel)
@with_error_handling("start_audiobook_stream")
@rate_limit(limit=3, window=60)  # 每分钟3个有声读物流
async def start_audiobook_stream(
    audiobook_id: str,
    request: AudoBookStreamRequestModel,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """开始有声读物流"""
    try:
        # 检查有声读物是否存在（简化实现）
        # 实际应该查询数据库
        
        # 生成会话ID
        session_id = str(uuid.uuid4())
        
        # 创建流配置
        config_data = request.config.dict() if request.config else {}
        stream_config = StreamConfig(**config_data)
        
        # 创建流管理器
        stream_manager = StreamManager(stream_config)
        
        # 创建有声读物音频源函数
        async def audiobook_source():
            # 这里应该获取有声读物文件
            # 简化实现，实际应该从数据库获取
            file_path = await _get_audiobook_file_path(audiobook_id, request.chapter)
            
            if not file_path:
                raise NotFoundError(f"有声读物 {audiobook_id} 不存在")
            
            return file_path
        
        # 开始流传输
        success = await stream_manager.start_streaming(audiobook_source)
        
        if not success:
            raise BusinessLogicError("启动有声读物流传输失败")
        
        # 保存会话
        stream_sessions[session_id] = stream_manager
        
        # 记录审计日志
        audit_logger.log_user_action(
            user_id=current_user.get("sub"),
            action="start_audiobook_stream",
            resource="streaming",
            details={
                "session_id": session_id,
                "audiobook_id": audiobook_id,
                "chapter": request.chapter
            }
        )
        
        return StreamInfoModel(
            session_id=session_id,
            status=stream_manager.status.value,
            config=stream_config.__dict__,
            buffer_info=stream_manager.get_buffer_info(),
            metadata={"audiobook_id": audiobook_id, "chapter": request.chapter}
        )
        
    except Exception as e:
        if isinstance(e, (NotFoundError, BusinessLogicError)):
            raise
        raise BusinessLogicError(f"启动有声读物流失败: {str(e)}")


@router.get("/{session_id}/status", response_model=StreamStatusModel)
@with_error_handling("get_stream_status")
async def get_stream_status(
    session_id: str,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """获取流状态"""
    try:
        if session_id not in stream_sessions:
            raise NotFoundError(f"流会话 {session_id} 不存在")
        
        stream_manager = stream_sessions[session_id]
        buffer_info = stream_manager.get_buffer_info()
        
        return StreamStatusModel(
            status=stream_manager.status.value,
            buffer_size=buffer_info["size"],
            buffer_duration=buffer_info["duration"],
            is_full=buffer_info["is_full"],
            is_empty=buffer_info["is_empty"]
        )
        
    except Exception as e:
        if isinstance(e, NotFoundError):
            raise
        raise BusinessLogicError(f"获取流状态失败: {str(e)}")


@router.post("/{session_id}/pause")
@with_error_handling("pause_stream")
async def pause_stream(
    session_id: str,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """暂停流"""
    try:
        if session_id not in stream_sessions:
            raise NotFoundError(f"流会话 {session_id} 不存在")
        
        stream_manager = stream_sessions[session_id]
        await stream_manager.pause_streaming()
        
        # 记录审计日志
        audit_logger.log_user_action(
            user_id=current_user.get("sub"),
            action="pause_stream",
            resource="streaming",
            details={"session_id": session_id}
        )
        
        return {
            "success": True,
            "message": f"流会话 {session_id} 已暂停",
            "status": stream_manager.status.value
        }
        
    except Exception as e:
        if isinstance(e, NotFoundError):
            raise
        raise BusinessLogicError(f"暂停流失败: {str(e)}")


@router.post("/{session_id}/resume")
@with_error_handling("resume_stream")
async def resume_stream(
    session_id: str,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """恢复流"""
    try:
        if session_id not in stream_sessions:
            raise NotFoundError(f"流会话 {session_id} 不存在")
        
        stream_manager = stream_sessions[session_id]
        await stream_manager.resume_streaming()
        
        # 记录审计日志
        audit_logger.log_user_action(
            user_id=current_user.get("sub"),
            action="resume_stream",
            resource="streaming",
            details={"session_id": session_id}
        )
        
        return {
            "success": True,
            "message": f"流会话 {session_id} 已恢复",
            "status": stream_manager.status.value
        }
        
    except Exception as e:
        if isinstance(e, NotFoundError):
            raise
        raise BusinessLogicError(f"恢复流失败: {str(e)}")


@router.post("/{session_id}/stop")
@with_error_handling("stop_stream")
async def stop_stream(
    session_id: str,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """停止流"""
    try:
        if session_id not in stream_sessions:
            raise NotFoundError(f"流会话 {session_id} 不存在")
        
        stream_manager = stream_sessions[session_id]
        await stream_manager.stop_streaming()
        await stream_manager.cleanup()
        
        # 移除会话
        del stream_sessions[session_id]
        
        # 记录审计日志
        audit_logger.log_user_action(
            user_id=current_user.get("sub"),
            action="stop_stream",
            resource="streaming",
            details={"session_id": session_id}
        )
        
        return {
            "success": True,
            "message": f"流会话 {session_id} 已停止并清理"
        }
        
    except Exception as e:
        if isinstance(e, NotFoundError):
            raise
        raise BusinessLogicError(f"停止流失败: {str(e)}")


@router.get("/{session_id}/stream")
@with_error_handling("stream_audio")
async def stream_audio(
    session_id: str,
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """获取音频流"""
    try:
        if session_id not in stream_sessions:
            raise NotFoundError(f"流会话 {session_id} 不存在")
        
        stream_manager = stream_sessions[session_id]
        
        # 生成音频流
        async def generate_audio_stream():
            try:
                while True:
                    # 读取音频块
                    chunk = await stream_manager.read_chunk()
                    
                    if chunk is None:
                        # 如果没有数据，等待一段时间
                        await asyncio.sleep(0.1)
                        continue
                    
                    if stream_manager.status == StreamStatus.STOPPED:
                        break
                    
                    if chunk.data:
                        yield chunk.data
                    
            except Exception as e:
                print(f"流传输错误: {e}")
            finally:
                # 确保清理
                if session_id in stream_sessions:
                    stream_manager = stream_sessions[session_id]
                    await stream_manager.cleanup()
                    del stream_sessions[session_id]
        
        return StreamingResponse(
            generate_audio_stream(),
            media_type="audio/octet-stream",
            headers={
                "Cache-Control": "no-cache",
                "Connection": "keep-alive"
            }
        )
        
    except Exception as e:
        if isinstance(e, NotFoundError):
            raise
        raise BusinessLogicError(f"获取音频流失败: {str(e)}")


@router.get("/")
@with_error_handling("list_streams")
async def list_streams(
    current_user: Dict[str, Any] = Depends(get_current_user)
):
    """列出所有活跃流"""
    try:
        active_streams = []
        
        for session_id, stream_manager in stream_sessions.items():
            buffer_info = stream_manager.get_buffer_info()
            
            active_streams.append({
                "session_id": session_id,
                "status": stream_manager.status.value,
                "buffer_info": buffer_info,
                "created_at": datetime.utcnow().isoformat()
            })
        
        return {
            "active_streams": active_streams,
            "total_count": len(active_streams)
        }
        
    except Exception as e:
        raise BusinessLogicError(f"获取流列表失败: {str(e)}")


@router.websocket("/ws/{session_id}")
async def websocket_stream(
    websocket: WebSocket,
    session_id: str
):
    """WebSocket流传输"""
    try:
        await websocket.accept()
        
        if session_id not in stream_sessions:
            await websocket.send_json({
                "type": "error",
                "message": f"流会话 {session_id} 不存在"
            })
            return
        
        stream_manager = stream_sessions[session_id]
        
        # 设置回调函数
        async def on_chunk_added(data, duration):
            await websocket.send_json({
                "type": "chunk_added",
                "data_size": len(data),
                "duration": duration
            })
        
        async def on_buffer_update(buffer_info):
            await websocket.send_json({
                "type": "buffer_update",
                "buffer_info": buffer_info
            })
        
        async def on_status_change(status):
            await websocket.send_json({
                "type": "status_change",
                "status": status.value
            })
        
        async def on_error(error_message):
            await websocket.send_json({
                "type": "error",
                "message": error_message
            })
        
        # 添加回调
        stream_manager.add_callback("on_chunk", on_chunk_added)
        stream_manager.add_callback("on_buffer_update", on_buffer_update)
        stream_manager.add_callback("on_status_change", on_status_change)
        stream_manager.add_callback("on_error", on_error)
        
        # 发送初始状态
        await websocket.send_json({
            "type": "connected",
            "session_id": session_id,
            "status": stream_manager.status.value,
            "buffer_info": stream_manager.get_buffer_info()
        })
        
        # 保持连接
        try:
            while True:
                # 接收客户端消息
                message = await websocket.receive_text()
                
                try:
                    data = json.loads(message)
                    
                    if data.get("type") == "pause":
                        await stream_manager.pause_streaming()
                    elif data.get("type") == "resume":
                        await stream_manager.resume_streaming()
                    elif data.get("type") == "stop":
                        await stream_manager.stop_streaming()
                        break
                    elif data.get("type") == "get_status":
                        await websocket.send_json({
                            "type": "status",
                            "status": stream_manager.status.value,
                            "buffer_info": stream_manager.get_buffer_info()
                        })
                    
                except json.JSONDecodeError:
                    await websocket.send_json({
                        "type": "error",
                        "message": "无效的JSON消息"
                    })
                    
        except WebSocketDisconnect:
            # 客户端断开连接
            pass
        
        finally:
            # 清理回调
            stream_manager.remove_callback("on_chunk", on_chunk_added)
            stream_manager.remove_callback("on_buffer_update", on_buffer_update)
            stream_manager.remove_callback("on_status_change", on_status_change)
            stream_manager.remove_callback("on_error", on_error)
            
    except Exception as e:
        print(f"WebSocket流传输错误: {e}")


# 辅助函数
async def _get_audiobook_file_path(audiobook_id: str, chapter: Optional[int]) -> Optional[str]:
    """获取有声读物文件路径"""
    # 简化实现，实际应该查询数据库
    return f"/data/audiobooks/{audiobook_id}/chapter_{chapter or 0}.mp3"


# 清理函数（定期清理不活跃的会话）
async def cleanup_inactive_streams():
    """清理不活跃的流会话"""
    while True:
        try:
            inactive_sessions = []
            
            for session_id, stream_manager in stream_sessions.items():
                # 如果流状态为停止或错误，清理
                if stream_manager.status in [StreamStatus.STOPPED, StreamStatus.ERROR]:
                    inactive_sessions.append(session_id)
            
            for session_id in inactive_sessions:
                stream_manager = stream_sessions[session_id]
                await stream_manager.cleanup()
                del stream_sessions[session_id]
                print(f"清理不活跃流会话: {session_id}")
            
            # 每5分钟清理一次
            await asyncio.sleep(300)
            
        except Exception as e:
            print(f"清理流会话错误: {e}")


# 清理任务将在应用启动时启动
# asyncio.create_task(cleanup_inactive_streams())
